#pragma once

#include <string>
#include <vector>
#include <json/json.h>  // jsoncpp

struct VideoInfo {
    std::string video_index;
    std::string video_type;
    std::vector<std::string> switchable_video_types;

    bool fromJson(const Json::Value& val) {
        if (!val.isObject()) return false;
        if (!val["video_index"].isString()) return false;
        if (!val["video_type"].isString()) return false;
        if (!val["switchable_video_types"].isArray()) return false;

        video_index = val["video_index"].asString();
        video_type = val["video_type"].asString();
        switchable_video_types.clear();
        for (const auto& v : val["switchable_video_types"])
            switchable_video_types.push_back(v.asString());

        return true;
    }

    Json::Value toJson() const {
        Json::Value val;
        val["video_index"] = video_index;
        val["video_type"] = video_type;
        Json::Value arr(Json::arrayValue);
        for (const auto& v : switchable_video_types)
            arr.append(v);
        val["switchable_video_types"] = arr;
        return val;
    }
};

struct CameraInfo {
    std::string camera_index;
    int available_video_number;
    int coexist_video_number_max;
    std::vector<VideoInfo> video_list;

    bool fromJson(const Json::Value& val) {
        if (!val.isObject()) return false;
        if (!val["camera_index"].isString()) return false;
        if (!val["available_video_number"].isInt()) return false;
        if (!val["coexist_video_number_max"].isInt()) return false;
        if (!val["video_list"].isArray()) return false;

        camera_index = val["camera_index"].asString();
        available_video_number = val["available_video_number"].asInt();
        coexist_video_number_max = val["coexist_video_number_max"].asInt();

        video_list.clear();
        for (const auto& v : val["video_list"]) {
            VideoInfo vi;
            if (vi.fromJson(v)) {
                video_list.push_back(vi);
            }
        }
        return true;
    }

    Json::Value toJson() const {
        Json::Value val;
        val["camera_index"] = camera_index;
        val["available_video_number"] = available_video_number;
        val["coexist_video_number_max"] = coexist_video_number_max;
        Json::Value arr(Json::arrayValue);
        for (const auto& vi : video_list)
            arr.append(vi.toJson());
        val["video_list"] = arr;
        return val;
    }
};

struct DeviceInfo {
    std::string sn;
    int available_video_number;
    int coexist_video_number_max;
    std::vector<CameraInfo> camera_list;

    bool fromJson(const Json::Value& val) {
        if (!val.isObject()) return false;
        if (!val["sn"].isString()) return false;
        if (!val["available_video_number"].isInt()) return false;
        if (!val["coexist_video_number_max"].isInt()) return false;
        if (!val["camera_list"].isArray()) return false;

        sn = val["sn"].asString();
        available_video_number = val["available_video_number"].asInt();
        coexist_video_number_max = val["coexist_video_number_max"].asInt();

        camera_list.clear();
        for (const auto& c : val["camera_list"]) {
            CameraInfo ci;
            if (ci.fromJson(c)) {
                camera_list.push_back(ci);
            }
        }
        return true;
    }

    Json::Value toJson() const {
        Json::Value val;
        val["sn"] = sn;
        val["available_video_number"] = available_video_number;
        val["coexist_video_number_max"] = coexist_video_number_max;
        Json::Value arr(Json::arrayValue);
        for (const auto& ci : camera_list)
            arr.append(ci.toJson());
        val["camera_list"] = arr;
        return val;
    }
};

struct LiveCapacityConfig {
    int available_video_number;
    int coexist_video_number_max;
    std::vector<DeviceInfo> device_list;

    bool fromJson(const Json::Value& val) {
        if (!val.isObject()) return false;
        if (!val["available_video_number"].isInt()) return false;
        if (!val["coexist_video_number_max"].isInt()) return false;
        if (!val["device_list"].isArray()) return false;

        available_video_number = val["available_video_number"].asInt();
        coexist_video_number_max = val["coexist_video_number_max"].asInt();

        device_list.clear();
        for (const auto& d : val["device_list"]) {
            DeviceInfo di;
            if (di.fromJson(d)) {
                device_list.push_back(di);
            }
        }
        return true;
    }

    Json::Value toJson() const {
        Json::Value val;
        val["available_video_number"] = available_video_number;
        val["coexist_video_number_max"] = coexist_video_number_max;
        Json::Value arr(Json::arrayValue);
        for (const auto& di : device_list)
            arr.append(di.toJson());
        val["device_list"] = arr;
        return val;
    }
};
